﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ServiceStack.Redis;

namespace yule.Common.Cache
{

    /// <summary>
    /// redis缓存
    /// </summary>
    internal class RedisCacheStrategy : BaseCacheStrategy
    {

        private static PooledRedisClientManager CreateManager(
            string readWriteHostsStr, string readOnlyHostsStr)
        {
            string[] readWriteHosts = readWriteHostsStr.Split(',');
            string[] readOnlyHosts = readWriteHostsStr.Split(',');

            return new PooledRedisClientManager(readWriteHosts, readOnlyHosts,
                new RedisClientManagerConfig
                {
                    MaxWritePoolSize = readWriteHosts.Length * 2,
                    MaxReadPoolSize = readOnlyHosts.Length * 2,
                    AutoStart = true,
                });
        }

        private static PooledRedisClientManager _prcm = null;

        private static object _prcm_lock = new object();

        private PooledRedisClientManager PRCM
        {
            get
            {
                if (_prcm == null)
                {
                    lock (_prcm_lock)
                    {
                        if (_prcm == null)
                        {
                            //测试连接
                            try
                            {
                                _prcm = CreateManager(
                                    yule.Util.AppSettings.GetAppSetting(yule.Const.AppSettings.ReadWriteHosts),
                                    yule.Util.AppSettings.GetAppSetting(yule.Const.AppSettings.ReadOnlyHosts));

                                using (IRedisClient redis = _prcm.GetReadOnlyClient())
                                {
                                    redis.GetAllKeys();
                                }
                            }
                            catch
                            {
                                _prcm = null;
                            }
                        }
                    }
                }
                return _prcm;
            }
        }

        public override bool Set<T>(string key, T obj) 
        {
            using (IRedisClient redis = PRCM.GetClient())
            {
                string tkey = GetCacheKey<T>(key);
                return redis.Set<T>(tkey, obj);
            }
        }

        public override T Get<T>(string key)
        {
            using (IRedisClient redis = PRCM.GetReadOnlyClient())
            {

                string tkey = GetCacheKey<T>(key);

                if (redis.ContainsKey(tkey))
                {
                    return redis.Get<T>(tkey);
                }
                else
                {
                    return default(T);
                }
            }
        }

        public override bool Remove<T>(string key) 
        {
            using (IRedisClient redis = PRCM.GetClient())
            {
                string tkey = GetCacheKey<T>(key);
                return redis.Remove(tkey);
            }
        }

        public List<string> GetAllKeys()
        {
            using (IRedisClient redis = PRCM.GetReadOnlyClient())
            {
                return redis.GetAllKeys();
            }
        }

        public override IList<T> Get<T>()
        {
            using (IRedisClient redis = PRCM.GetReadOnlyClient())
            {
                IList<string> keys = redis.GetAllKeys();
                string key = this.GetTypeKey<T>();

                IList<T> list = new List<T>();

                if (keys != null && keys.Count > 0)
                {
                    foreach (string k in keys)
                    {
                        if (k.StartsWith(key) == true)
                        {
                            list.Add(redis.Get<T>(k));
                        }
                    }
                }

                return list;
            }
        }

        public override bool Remove<T>()
        {
            using (IRedisClient redis = PRCM.GetReadOnlyClient())
            {
                IList<string> keys = redis.GetAllKeys();
                string key = this.GetTypeKey<T>();

                if (keys != null && keys.Count > 0)
                {
                    foreach (string k in keys)
                    {
                        if (k.StartsWith(key) == true)
                        {
                            redis.Remove(k);
                        }
                    }
                }
                return true;
            }
        }

    }
}